#ifndef SERIAL_PORT_H
#define SERIAL_PORT_H

#include <string>
#include <vector>
#include <cstdint>
#include <functional>
#include <thread>
#include <atomic>

#ifdef _WIN32
#include <windows.h>
#else
#include <termios.h>
#include <unistd.h>
#endif

enum class Baudrate : unsigned long
{
    BAUDRATE_0          = 0,
    BAUDRATE_50         = 50,
    BAUDRATE_75         = 75,
    BAUDRATE_110        = 110,
    BAUDRATE_134        = 134,
    BAUDRATE_150        = 150,
    BAUDRATE_200        = 200,
    BAUDRATE_300        = 300,
    BAUDRATE_600        = 600,
    BAUDRATE_1200       = 1200,
    BAUDRATE_1800       = 1800,
    BAUDRATE_2400       = 2400,
    BAUDRATE_4800       = 4800,
    BAUDRATE_9600       = 9600,
    BAUDRATE_14400      = 14400,
    BAUDRATE_19200      = 19200,
    BAUDRATE_38400      = 38400,
    BAUDRATE_57600      = 57600,
    BAUDRATE_115200     = 115200,
    BAUDRATE_230400     = 230400,
#ifdef _WIN32
    BAUDRATE_256000     = 256000,
#endif
    BAUDRATE_460800     = 460800,
    BAUDRATE_500000     = 500000,
    BAUDRATE_576000     = 576000,
    BAUDRATE_921600     = 921600,
    BAUDRATE_1000000    = 1000000,
    BAUDRATE_1152000    = 1152000,
    BAUDRATE_2000000    = 2000000,
    BAUDRATE_2500000    = 2500000,
    BAUDRATE_3000000    = 3000000,
    BAUDRATE_3500000    = 3500000,
    BAUDRATE_4000000    = 4000000,
};

enum class DataBit : unsigned char
{
    DATABIT_5 = 5,
    DATABIT_6 = 6,
    DATABIT_7 = 7,
    DATABIT_8 = 8
};

enum class Parity
{
    NONE    = 0,
    ODD     = 1,
    EVEN    = 2,
    MARK    = 3,
    SPACE   = 4
};

enum class StopBits : unsigned char
{
    ONE     = 0,
    ONE5    = 1,
    TWO     = 2,
};

struct SerialPortInfo {
    std::string port;
    std::string description;
};

typedef struct PortParam_t
{
    std::string     portName;
    Baudrate        baudRate;
    DataBit         dataBits;
    Parity          parity;
    StopBits        stopBits;
}PortParam;

class SerialPort {
public:
    using DataCallback = std::function<void(const uint8_t* data, size_t size)>;

    SerialPort();
    ~SerialPort();

    SerialPort(const SerialPort&) = delete;
    SerialPort& operator=(const SerialPort&) = delete;
    SerialPort(SerialPort&& other) noexcept;
    SerialPort& operator=(SerialPort&& other) noexcept;

    // 检索串口通道
    static std::vector<SerialPortInfo> listAvailablePorts();

    // 打开串口
    bool openPort(const PortParam& param);
    // 关闭串口
    void closePort();

    // -- 新增的异步接收接口 --
    // 启动后台接收线程
    bool enableReceive(DataCallback callback);
    // 停止后台接收线程
    void disableReceive();
    // 串口接收数据
    int32_t serialReceive(uint8_t* buffer, int bufferSize);

    // 串口发送数据
    int32_t serialTransmit(const uint8_t* data, int dataSize);
    // 获取串口状态
    void getStatus(uint64_t& bytesSent, uint64_t& bytesReceived, std::string& errorInfo);
    // 检查串口开关状态
    [[nodiscard]] bool isOpen() const;

#ifndef _WIN32
    int32_t getFd() const;
#endif

private:
    void receiveLoop();
    // 设置串口参数
    bool setPortParameters(const PortParam& param);

    std::string     currentPortName;        // 当前端口名称
    bool            portOpen;               // 是否打开
    uint64_t        totalBytesSent;         // 发送总字节数
    uint64_t        totalBytesReceived;     // 接收总字节数
    std::string     lastErrorInfo;          // 最后一次错误信息

    std::thread     receiveThread;     // 后台接收线程对象
    std::atomic<bool> receiving;       // 控制接收线程循环的原子标志
    DataCallback    dataCallback;      // 用户提供的数据回调函数

#ifdef _WIN32
    HANDLE          hSerial;                //  串口句柄
#else
    int32_t         fd;
    struct termios  tty{};
#endif
};

#endif // SERIAL_PORT_H
